﻿using AJWPFAdmin.Core.Enums;
using AJWPFAdmin.Core.ExtensionMethods;
using AJWPFAdmin.Core.Logger;
using AJWPFAdmin.Core.Models.EF.Tables;
using AJWPFAdmin.Core.Utils;
using AJWPFAdmin.Services.EF;
using AJWPFAdmin.Services.EF.TableExts;
using Dapper;
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;
using Quartz.Util;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AJWPFAdmin.Services.AppointAPI.GoodsInfoQuery
{
    public class SongTingGoodsInfoQuery : GoodsInfoQueryBase
    {
        private static readonly Dictionary<string, string> _goodsTypeMaps = new Dictionary<string, string>
        {
            {"01","原料" },
            {"02","燃料" },
            {"03","辅料" },
            {"04","工业气体" },
            {"07","废旧物资" },
            {"08","中间产品" },
            {"09","产成品" },
            {"10","副产品" },
            {"11","设备备件" },
            {"90","内部倒运物资" },
            {"91","其它计里物资" },
        };

        private AJLog4NetLogger _logger;

        private DbService _customerDb;

        public SongTingGoodsInfoQuery(AJConfigService cfgSvc, DefaultAppointAPI.APIConfig apiConfig, AJLog4NetLogger logger, GoodsInfoQueryTemplate name) : base(cfgSvc, apiConfig, name)
        {
            _logger = logger;

            if (string.IsNullOrWhiteSpace(apiConfig.DbServer) || string.IsNullOrWhiteSpace(apiConfig.QueryTemplate))
            {
                return;
            }

            var connBuilder = new SqlConnectionStringBuilder
            {
                DataSource = apiConfig.DbServer,
                UserID = apiConfig.DbUserId,
                Password = apiConfig.DbPassword,
                Encrypt = true,
                TrustServerCertificate = true,
                MultipleActiveResultSets = true,
            };
            var builder = new DbContextOptionsBuilder<DbService>();
            builder.UseSqlServer(connBuilder.ConnectionString, bd =>
            {
                bd.CommandTimeout(15);
                bd.EnableRetryOnFailure(3);
            });

            _customerDb = new DbService(builder.Options);
        }

        public override void FillGoodsInfo(ref Car carInfo, WeighingDataCache dataCache)
        {
            carInfo.Code = dataCache.TicketCode;
            carInfo.Sender = dataCache.Sender;
            carInfo.Receiver = dataCache.Receiver;
            carInfo.SendOrReceiveFlag = dataCache.SendOrReceiveFlag;

            if (carInfo.SendOrReceiveFlag == "0")
            {
                carInfo.InGoodsName = dataCache.GoodsName;
                carInfo.InGoodsVolume = dataCache.Reserve2.TryGetDecimal();
                carInfo.InGoodsType = dataCache.GoodsType;
            }
            else
            {
                carInfo.OutGoodsName = dataCache.GoodsName;
                carInfo.OutGoodsVolume = dataCache.Reserve2.TryGetDecimal();
                carInfo.OutGoodsType = dataCache.GoodsType;
            }
        }

        public override async Task<WeighingDataCache> QueryAsync(CarInfoParams carInfoParams)
        {
            if (_db == null)
            {
                return null;
            }
            ////TODO: 本地调试模式, 直接返回空,啥也不做
            //return null;

            var result = new WeighingDataCache();

            var carInfo = carInfoParams.CarInfo;

            var carNo = carInfo.CarNo;

            ////TODO: 本地调试模式,上线后注释, 入厂, 返回: 收发标记0, 出厂5 ,派车单随意
            //result.Code = "123456789";
            //result.SendOrReceiveFlag = PassagewayDirection.出 == carInfoParams.Passageway?.Direction ? "5" : "0";
            //result.Weight = PassagewayDirection.出 == carInfoParams.Passageway?.Direction ? "11" : "0";
            //result.Name = PassagewayDirection.出 == carInfoParams.Passageway?.Direction ? "出厂测试001" : "进厂测试002";
            //result.GoodsType = PassagewayDirection.出 == carInfoParams.Passageway?.Direction ? "out_type" : "in_type";
            //return result;

            var conn = _customerDb.Database.GetDbConnection();

            /*
             * 1 车辆入场，根据车牌tmp_plate，读取收发标志 sfbz，和派车单号 pczh

                string.Format("select bfpcd_sfbz,bfpcd_pczh,bfpcd_clbh,bfpcd_wlbh,bfpcd_yssl from bfpcd where  bfpcd_clbh = '{0}' and (bfpcd_djbz is null or bfpcd_djbz='计划') and (bfpcd_hsbz='0' or bfpcd_hsbz='8') ", tmp_plate);
            */

            var now = DateTime.Now;

            var start = now.Date.AddHours(-24);

            var paiCheDanSource = await conn.QueryAsync<SongTingPaiCheDan>($"select bfpcd_sfbz as {nameof(SongTingPaiCheDan.Flag)},bfpcd_pczh as {nameof(SongTingPaiCheDan.Code)}, bfpcd_rq as {nameof(SongTingPaiCheDan.Date)},bfpcd_c5 as {nameof(SongTingPaiCheDan.Time)} from bfpcd where bfpcd_clbh = @carNo and (bfpcd_djbz is null or bfpcd_djbz='计划') and (bfpcd_hsbz='0' or bfpcd_hsbz='8')", new { carNo });

            var paiCheDanList = paiCheDanSource == null ? new List<SongTingPaiCheDan>() : paiCheDanSource.ToList();

            var loggerBuilder = new StringBuilder();

            loggerBuilder.AppendLine($"{carNo} 查询派车单表结果:{CommonUtil.AJSerializeObject(paiCheDanList)}");

            var paiCheDan = paiCheDanList.FirstOrDefault(p => p.Flag == "0");
            if (paiCheDan == null)
            {
                loggerBuilder.AppendLine($"未查找到0标志,继续查找标志1或5");
                paiCheDanList.ForEach(p => p.CalculateDateTime());
                paiCheDan = paiCheDanList
                    .Where(p => p.Flag == "5" || p.Flag == "1"
                    && p.TheDateTime.HasValue
                    && now.Subtract(p.TheDateTime.GetValueOrDefault()).TotalHours < 48)
                    .OrderByDescending(p => p.TheDateTime).FirstOrDefault();
            }

            if (paiCheDan != null)
            {
                loggerBuilder.AppendLine($"查找到派车单,收发标志:{paiCheDan.Flag},派车单号:{paiCheDan.Code}");
            }
            else
            {
                loggerBuilder.AppendLine($"未找到派车单信息");
            }

            paiCheDan ??= new SongTingPaiCheDan();

            // 如果没有查询到单号和收发标记
            if (string.IsNullOrWhiteSpace(paiCheDan.Flag))
            {
                // 如果是出，检查车辆信息中是否存在单号和标记
                if (PassagewayDirection.出 == carInfoParams.Passageway?.Direction)
                {
                    loggerBuilder.Append($"出厂,将使用最近入厂记录的收发标记:");
                    if (!string.IsNullOrWhiteSpace(carInfo.SendOrReceiveFlag))
                    {
                        loggerBuilder.Append(carInfo.SendOrReceiveFlag);
                        paiCheDan.Flag = carInfo.SendOrReceiveFlag;
                    }
                    loggerBuilder.Append($",将使用最近入厂记录的派车单号:");
                    if (!string.IsNullOrWhiteSpace(carInfo.Code))
                    {
                        loggerBuilder.Append(carInfo.Code);
                        paiCheDan.Code = carInfo.Code;
                    }
                }
                // 如果还是空， 则返回默认值
                if (string.IsNullOrWhiteSpace(paiCheDan.Code))
                {
                    loggerBuilder.AppendLine($"没有从数据库查询到任何数据,且最近入厂记录也没有数据,返回空数据");
                    _logger.Debug(loggerBuilder.ToString());
                    loggerBuilder.AppendLine($"最终返回结果:{CommonUtil.AJSerializeObject(result)}");
                    return result;
                }
            }

            /*
             * 2 车辆出场，如果收发标志sfbz为"0"，为收货，根据派车单号，读取发货单位，收货单位，物料编号，净重
                string.Format("select c16,c17,bfsfcl_wlbh,bfsfcl_jz from bfsfcl where bfsfcl_pczh = '{0}'", pczh); 
               c16发货单位,c17收货单位,物料编号,净重

                3 车辆出场，如果sfbz收发标志为"1"或"5"，为发货，根据派车单，读取收货单位，净重，物料编号
                string.Format("select shdw,fhdd,bffhcl_jz,bffhcl_wlbh from bffhcl where bffhcl_pczh = '{0}'", pczh);
            */

            var sfbz = result.SendOrReceiveFlag = paiCheDan.Flag;

            var pczh = result.TicketCode = paiCheDan.Code;

            // 进厂直接不查询物资了,只返回派车单和收发标志
            if (PassagewayDirection.进 == carInfoParams.Passageway?.Direction)
            {
                loggerBuilder.AppendLine($"进厂,只返回派车单和收发标志");
                _logger.Debug(loggerBuilder.ToString());
                loggerBuilder.AppendLine(CommonUtil.AJSerializeObject(result));
                return result;
            }

            loggerBuilder.AppendLine($"开始查询物资,收/发货单位");

            var tempResult = sfbz == "0" ?
                await conn.QueryFirstOrDefaultAsync<WeighingDataCache>($"select bfsfcl_c16 as {nameof(WeighingDataCache.Sender)},bfsfcl_c17 as {nameof(WeighingDataCache.Receiver)}, bfsfcl_wlbh as {nameof(WeighingDataCache.GoodsName)},bfsfcl_jz as {nameof(WeighingDataCache.Reserve2)} from bfsfcl where bfsfcl_pczh = @pczh order by bfsfcl_rq desc",
                new
                {
                    pczh
                })
                : await conn.QueryFirstOrDefaultAsync<WeighingDataCache>($"select bffhcl_shdw as {nameof(WeighingDataCache.Receiver)},bffhcl_fhdd as {nameof(WeighingDataCache.Sender)},bffhcl_jz as {nameof(WeighingDataCache.Reserve2)},bffhcl_wlbh  as {nameof(WeighingDataCache.GoodsName)} from bffhcl where bffhcl_pczh = @pczh order by bffhcl_rq desc", new
                {
                    pczh
                });

            /*
             * 4 根据物料编号，获取物料名称
                string.Format("select cinvname from inventory where cinvcode = '{0}'", wlbh);
             */

            if (tempResult != null)
            {
                loggerBuilder.AppendLine($"查询到数据:{CommonUtil.AJSerializeObject(tempResult)}");
            }
            else
            {
                loggerBuilder.AppendLine($"未查询到数据");
            }

            tempResult ??= new WeighingDataCache();

            if (sfbz != "0")
            {
                loggerBuilder.AppendLine($"收发标志是{sfbz},根据条件判断");

                // 如果是1 单品种发货, 收货单位就是查询所得收货单位

                result.Receiver = sfbz == "1" ? tempResult.Receiver : tempResult.Sender;
                result.Sender = tempResult.Sender = "唐山松汀钢铁有限公司";
                //loggerBuilder.AppendLine($"收发标志不是0,将判断是否使用默认发货单位:");
                //if (string.IsNullOrWhiteSpace(tempResult.Sender))
                //{
                //    loggerBuilder.Append($"默认发货单位");
                //    result.Sender = tempResult.Sender = "唐山松汀钢铁有限公司";
                //}
                //else
                //{
                //    loggerBuilder.Append($"使用查询的数据:{tempResult.Sender}");
                //    result.Sender = tempResult.Sender;
                //}
            }
            else
            {
                loggerBuilder.AppendLine($"收发标志是0,使用查询出来的数据");
                result.Sender = tempResult.Sender;
                result.Receiver = tempResult.Receiver;
            }

            if (string.IsNullOrWhiteSpace(tempResult.GoodsName))
            {
                loggerBuilder.AppendLine($"未查询到物资编码,忽略物资查询流程");
                loggerBuilder.AppendLine($"最终返回结果:{CommonUtil.AJSerializeObject(result)}");
                _logger.Debug(loggerBuilder.ToString());
                return result;
            }

            result.Reserve2 = tempResult.Reserve2;

            var cinvcode = result.GoodsName = tempResult.GoodsName;

            if (result.GoodsName.Length >= 2)
            {
                if (_goodsTypeMaps.TryGetValue(result.GoodsName.Substring(0, 2), out var type))
                {
                    result.GoodsType = type;
                }
            }

            var goodsName = await conn.QueryFirstOrDefaultAsync<string>($"select cinvname from inventory where cinvcode = @cinvcode", new { cinvcode });

            loggerBuilder.AppendLine(string.IsNullOrWhiteSpace(goodsName)
                ? $"未查询到物资名称"
                : $"查询到物资名称");

            if (!string.IsNullOrWhiteSpace(goodsName))
            {
                result.GoodsName = goodsName;
                loggerBuilder.AppendLine("查询到物资名称");
            }
            else
            {
                loggerBuilder.AppendLine("未查询到物资名称");
            }

            loggerBuilder.AppendLine($"最终返回结果:{CommonUtil.AJSerializeObject(result)}");
            _logger.Debug(loggerBuilder.ToString());

            return result;
        }

        public new void Dispose()
        {
            base.Dispose();
            _customerDb?.Dispose();
        }

        public class SongTingPaiCheDan
        {
            public string Code { get; set; }

            public string Flag { get; set; }

            public string Date { get; set; }

            public string Time { get; set; }

            public DateTime? TheDateTime
            {
                get; set;
            }

            public void CalculateDateTime()
            {
                if (DateTime.TryParseExact($"{Date} {Time}", "yyyyMMdd HH:mm:ss", null, System.Globalization.DateTimeStyles.None, out var b))
                {
                    TheDateTime = b;
                }
            }
        }
    }
}
